# -*- coding: utf-8 -*-
"""
HaaS506 RTU Modbus模块
简化版本 - Modbus RTU通信
温度：CMD_READ_TEMP = bytearray([0x0B, 0x04, 0x00, 0x00, 0x00, 0x02, 0x71, 0x61])
电压电流：CMD_READ_VOLT_CURRENT = bytearray([0x65, 0x03, 0x00, 0x00, 0x00, 0x06, 0xCD, 0xEC])
能耗：CMD_READ_POWER = bytearray([0x65, 0x03, 0x00, 0x1D, 0x00, 0x02, 0x5C, 0x29])
"""

import utime
from driver import UART
import rtu_config

# Modbus RTU状态
_uart = None
_last_read_time = 0


def init():
    """初始化Modbus模块"""
    global _uart

    try:
        _uart = UART()
        _uart.open("RS485")
        print("[MODBUS] Modbus RTU initialized")
        return True
    except Exception as e:
        print("[MODBUS] Init error: {}".format(e))
        return False


def read_temperature_humidity():
    """读取温湿度传感器数据"""
    result = {"temperature": -999, "humidity": -999, "debug": ""}

    try:
        # 使用固定的温度读取指令
        cmd = bytearray([0x0B, 0x04, 0x00, 0x00, 0x00, 0x02, 0x71, 0x61])

        # 清空接收缓冲区
        dummy_buffer = bytearray(64)
        _uart.read(dummy_buffer)

        # 发送指令
        _uart.write(cmd)
        utime.sleep_ms(200)

        # 读取响应
        response_buffer = bytearray(32)
        bytes_received = _uart.read(response_buffer)
        
        if bytes_received < 9:
            print("[MODBUS] No response received, bytes: {}".format(bytes_received))
            result["debug"] = "No response"
            return result

        response = response_buffer[:bytes_received]
        # result["debug"] = " ".join(["{:02X}".format(b) for b in response])

        # 响应至少应有9字节（地址+功能码+字节数+4字节数据+2字节CRC）
        if len(response) < 9:
            print("[MODBUS] Incomplete response: {} bytes".format(len(response)))
            return result

        # 简化校验：只判断地址与功能码
        if response[0] != 0x0B or response[1] != 0x04:
            print("[MODBUS] Unexpected response header")
            return result

        # 解析温湿度, 先交换字节顺序
        humi_raw = (response[3] << 8) | response[4]
        temp_raw = (response[5] << 8) | response[6]

        # 处理温度异常值
        if(temp_raw>3000):
            temp_raw = temp_raw - 65536
            
        result["temperature"] = temp_raw / 10.0
        result["humidity"] = humi_raw / 10.0

        return result

    except Exception as e:
        print("[MODBUS] Read temperature error: {}".format(e))
        debug = "[MODBUS] Read temperature error: {}".format(e)
        result["debug"] = debug
        return result


def read_three_phase_current():
    """读取三相电流数据（仅电流）"""
    try:
        # 使用固定的电压电流读取指令
        cmd = bytearray([0x65, 0x03, 0x00, 0x00, 0x00, 0x06, 0xCD, 0xEC])

        # 清空接收缓冲区
        dummy_buffer = bytearray(64)
        _uart.read(dummy_buffer)

        # 发送命令
        _uart.write(cmd)
        utime.sleep_ms(200)

        # 读取响应
        response_buffer = bytearray(32)
        bytes_received = _uart.read(response_buffer)

        # 3字节头 + 6*2字节数据 + 2字节CRC = 17字节
        if bytes_received < 17:
            print("[MODBUS] Three phase current no response, received {} bytes".format(bytes_received))
            return None

        response = response_buffer[:bytes_received]

        # 验证响应（地址固定为0x65）
        if not _validate_response(response, 0x65, 0x03, 17):
            return None

        # 解析三相电流数据（跳过电压数据）
        current_a_raw = (response[9] << 8) | response[10]
        current_b_raw = (response[11] << 8) | response[12]
        current_c_raw = (response[13] << 8) | response[14]

        # 转换为实际值
        current_a = current_a_raw / 100.0
        current_b = current_b_raw / 100.0
        current_c = current_c_raw / 100.0

        return {
            "current_a": current_a,
            "current_b": current_b,
            "current_c": current_c,
        }

    except Exception as e:
        print("[MODBUS] Read three phase current error: {}".format(e))
        return None


def read_power_meter():
    """读取电力仪表数据"""
    config = rtu_config.get_config("modbus.power_meter", {})
    address = config.get("address", 101)

    # 验证地址范围
    if not (1 <= address <= 247):
        print("[MODBUS] Invalid device address: {}".format(address))
        return None

    # 读取三相数据（包含了所有需要的信息）
    three_phase_data = _read_three_phase_data(address)
    if not three_phase_data:
        # 如果三相数据读取失败，尝试读取基本数据
        print("[MODBUS] Three phase data read failed, trying basic data")
        basic_data = _read_basic_power_data(address)
        if basic_data:
            # 添加默认的三相数据
            basic_data.update(
                {
                    "voltage_a": -999.0,
                    "voltage_b": -999.0,
                    "voltage_c": -999.0,
                    "current_a": -999.0,
                    "current_b": -999.0,
                    "current_c": -999.0,
                }
            )
        return basic_data

    # 计算总电压（根据旧项目的逻辑）
    va = three_phase_data["voltage_a"]
    vb = three_phase_data["voltage_b"]
    vc = three_phase_data["voltage_c"]

    if vb == 0 and vc == 0:
        # 单相供电
        voltage_total = va
    else:
        # 三相供电，计算线电压
        voltage_total = (va + vb + vc) / 3 * 1.73

    # 计算总电流
    current_total = (
        three_phase_data["current_a"]
        + three_phase_data["current_b"]
        + three_phase_data["current_c"]
    )

    # 更新总电压和总电流
    three_phase_data["voltage"] = round(voltage_total, 1)
    three_phase_data["current"] = round(current_total, 3)

    # 读取功耗数据（如果需要）
    power_data = _read_power_consumption(address)
    if power_data:
        three_phase_data.update(power_data)
    else:
        # 使用默认值
        three_phase_data["power"] = 0
        three_phase_data["energy"] = 0

    return three_phase_data


def _read_basic_power_data(address):
    """读取基本电力数据（总电压、电流、功率、电能）"""
    max_retries = 2
    retry_count = 0

    while retry_count < max_retries:
        try:
            # 读取基本寄存器
            cmd = bytearray(
                [
                    address,  # 设备地址
                    0x03,  # 功能码：读保持寄存器
                    0x00,
                    0x00,  # 起始地址
                    0x00,
                    0x04,  # 寄存器数量(4个基本寄存器)
                ]
            )

            # 添加CRC校验
            crc = _calculate_crc(cmd)
            cmd.append(crc & 0xFF)  # CRC低字节
            cmd.append((crc >> 8) & 0xFF)  # CRC高字节

            # 清空接收缓冲区
            dummy_buffer = bytearray(64)
            _uart.read(dummy_buffer)

            # 发送命令（转换为bytes）
            _uart.write(bytes(cmd))
            # 增加等待时间，电表响应可能较慢
            utime.sleep_ms(200)  # 从100ms增加到200ms

            # 读取响应
            response_buffer = bytearray(64)
            bytes_received = _uart.read(response_buffer)

            # 基本数据只需要13字节
            # 3字节头 + 4*2字节数据 + 2字节CRC = 13字节
            if bytes_received < 13:
                retry_count += 1
                if retry_count < max_retries:
                    print(
                        "[MODBUS] Power meter no response or incomplete, retrying... ({}/{})".format(
                            retry_count, max_retries
                        )
                    )
                    utime.sleep_ms(300)  # 重试前等待300ms
                    continue
                else:
                    print(
                        "[MODBUS] Power meter no response after {} retries".format(
                            max_retries
                        )
                    )
                    return None

            response = response_buffer[:bytes_received]

            # 验证响应
            if not _validate_response(response, address, 0x03, 13):
                retry_count += 1
                if retry_count < max_retries:
                    print(
                        "[MODBUS] Invalid response, retrying... ({}/{})".format(
                            retry_count, max_retries
                        )
                    )
                    utime.sleep_ms(300)
                    continue
                else:
                    return None

            # 防止索引越界
            if len(response) < 13:
                print("[MODBUS] Response too short: {} bytes".format(len(response)))
                return None

            # 解析基本数据
            voltage_raw = (response[3] << 8) | response[4]
            current_raw = (response[5] << 8) | response[6]
            power_raw = (response[7] << 8) | response[8]
            energy_raw = (response[9] << 8) | response[10]  # 简化处理，只读2字节

            # 转换为实际值
            voltage = voltage_raw / 10.0
            current = current_raw / 100.0
            power = power_raw
            energy = energy_raw / 100.0

            # 验证数据合理性
            if not (0 <= voltage <= 1000):
                print("[MODBUS] Invalid voltage value: {}".format(voltage))
                retry_count += 1
                if retry_count < max_retries:
                    print(
                        "[MODBUS] Invalid data, retrying... ({}/{})".format(
                            retry_count, max_retries
                        )
                    )
                    utime.sleep_ms(300)
                    continue
                else:
                    return None

            if not (0 <= current <= 1000):
                print("[MODBUS] Invalid current value: {}".format(current))
                retry_count += 1
                if retry_count < max_retries:
                    print(
                        "[MODBUS] Invalid data, retrying... ({}/{})".format(
                            retry_count, max_retries
                        )
                    )
                    utime.sleep_ms(300)
                    continue
                else:
                    return None

            # 数据有效，返回结果
            print(
                "[MODBUS] Basic power meter read success: V={:.1f}V, I={:.2f}A, E={:.2f}kWh".format(
                    voltage, current, energy
                )
            )

            return {
                "voltage": voltage,
                "current": current,
                "power": power,
                "energy": energy,
            }

        except Exception as e:
            retry_count += 1
            if retry_count < max_retries:
                print(
                    "[MODBUS] Read basic power meter error: {}, retrying... ({}/{})".format(
                        e, retry_count, max_retries
                    )
                )
                utime.sleep_ms(300)
                continue
            else:
                print(
                    "[MODBUS] Read basic power meter error after {} retries: {}".format(
                        max_retries, e
                    )
                )
                return None

    # 如果所有重试都失败了
    return None


def _read_three_phase_data(address, start_register=0x0000):
    """读取三相电压电流数据"""
    try:
        # 使用固定的电压电流读取指令
        cmd = bytearray([0x65, 0x03, 0x00, 0x00, 0x00, 0x06, 0xCD, 0xEC])

        # 清空接收缓冲区
        dummy_buffer = bytearray(64)
        _uart.read(dummy_buffer)

        # 发送命令
        _uart.write(cmd)
        utime.sleep_ms(200)

        # 读取响应
        response_buffer = bytearray(32)
        bytes_received = _uart.read(response_buffer)

        # 3字节头 + 6*2字节数据 + 2字节CRC = 17字节
        if bytes_received < 17:
            print(
                "[MODBUS] Three phase data no response, received {} bytes".format(
                    bytes_received
                )
            )
            return None

        response = response_buffer[:bytes_received]

        # 打印原始数据用于调试
        print(
            "[MODBUS] Three phase raw response: {}".format(
                " ".join(["{:02X}".format(b) for b in response])
            )
        )

        # 验证响应（地址固定为0x65）
        if not _validate_response(response, 0x65, 0x03, 17):
            return None

        # 解析三相数据
        voltage_a_raw = (response[3] << 8) | response[4]
        voltage_b_raw = (response[5] << 8) | response[6]
        voltage_c_raw = (response[7] << 8) | response[8]
        current_a_raw = (response[9] << 8) | response[10]
        current_b_raw = (response[11] << 8) | response[12]
        current_c_raw = (response[13] << 8) | response[14]

        # 转换为实际值
        voltage_a = voltage_a_raw / 10.0
        voltage_b = voltage_b_raw / 10.0
        voltage_c = voltage_c_raw / 10.0
        current_a = current_a_raw / 100.0
        current_b = current_b_raw / 100.0
        current_c = current_c_raw / 100.0

        print(
            "[MODBUS] Three phase data: VA={:.1f}V, VB={:.1f}V, VC={:.1f}V, IA={:.2f}A, IB={:.2f}A, IC={:.2f}A".format(
                voltage_a, voltage_b, voltage_c, current_a, current_b, current_c
            )
        )

        return {
            "voltage_a": voltage_a,
            "voltage_b": voltage_b,
            "voltage_c": voltage_c,
            "current_a": current_a,
            "current_b": current_b,
            "current_c": current_c,
        }

    except Exception as e:
        print("[MODBUS] Read three phase data error: {}".format(e))
        return None


def _read_power_consumption(address):
    """读取功耗数据（电能）"""
    try:
        # 使用固定的能耗读取指令
        cmd = bytearray([0x65, 0x03, 0x00, 0x1D, 0x00, 0x02, 0x5C, 0x29])

        # 清空接收缓冲区
        dummy_buffer = bytearray(64)
        _uart.read(dummy_buffer)

        # 发送命令
        _uart.write(cmd)
        utime.sleep_ms(200)

        # 读取响应
        response_buffer = bytearray(16)
        bytes_received = _uart.read(response_buffer)

        # 3字节头 + 2*2字节数据 + 2字节CRC = 9字节
        if bytes_received < 9:
            print("[MODBUS] Power consumption no response")
            return None

        response = response_buffer[:bytes_received]

        # 验证响应（地址固定为0x65）
        if not _validate_response(response, 0x65, 0x03, 9):
            return None

        # 解析数据：功耗 = ((高位*256+次高位)*256+ (次低位*256+低位))/100 KWH
        high_word = (response[3] << 8) | response[4]
        low_word = (response[5] << 8) | response[6]
        energy_raw = (high_word << 16) | low_word
        energy = energy_raw / 100.0

        print("[MODBUS] Power consumption: {:.2f} kWh".format(energy))

        return {"energy": round(energy, 2), "power": 0}  # 功率数据不在这里

    except Exception as e:
        print("[MODBUS] Read power consumption error: {}".format(e))
        return None


def read_all_devices():
    """读取所有设备数据"""
    data = {}

    # 读取温湿度数据
    temp_data = read_temperature_humidity()
    if temp_data:
        data.update(temp_data)

    # 读取电力数据
    power_data = read_power_meter()
    if power_data:
        data.update(power_data)

    return data if data else None


def _calculate_crc(data):
    """计算CRC16校验"""
    crc = 0xFFFF

    for byte in data:
        crc ^= byte
        for _ in range(8):
            if crc & 0x0001:
                crc >>= 1
                crc ^= 0xA001
            else:
                crc >>= 1

    return crc


def _validate_response(response, expected_addr, expected_func, min_length):
    """验证Modbus响应"""
    try:
        # 检查最小长度
        if len(response) < min_length:
            print(
                "[MODBUS] Response too short: {} < {}".format(len(response), min_length)
            )
            return False

        # 检查设备地址
        if response[0] != expected_addr:
            print(
                "[MODBUS] Wrong device address: {} != {}".format(
                    response[0], expected_addr
                )
            )
            return False

        # 检查功能码
        if response[1] != expected_func:
            # 检查是否是异常响应
            if response[1] == (expected_func | 0x80):
                print("[MODBUS] Exception response: code {}".format(response[2]))
            else:
                print(
                    "[MODBUS] Wrong function code: {} != {}".format(
                        response[1], expected_func
                    )
                )
            return False

        # 验证CRC
        data_len = len(response) - 2
        calculated_crc = _calculate_crc(response[:data_len])
        received_crc = response[data_len] | (response[data_len + 1] << 8)

        if calculated_crc != received_crc:
            print(
                "[MODBUS] CRC error: calc={:04X}, recv={:04X}".format(
                    calculated_crc, received_crc
                )
            )
            return False

        return True

    except Exception as e:
        print("[MODBUS] Validate response error: {}".format(e))
        return False


def scan_power_meter_registers(start_addr=0x0000, end_addr=0x0100, count=6):
    """扫描电表寄存器，查找三相数据"""
    config = rtu_config.get_config("modbus.power_meter", {})
    address = config.get("address", 101)

    print(
        "[MODBUS] Scanning power meter registers from 0x{:04X} to 0x{:04X}".format(
            start_addr, end_addr
        )
    )
    print("[MODBUS] Device address: {}".format(address))

    # 验证地址范围
    if not (1 <= address <= 247):
        print("[MODBUS] Invalid device address: {}".format(address))
        return

    # 扫描寄存器
    for reg_addr in range(start_addr, end_addr, count):
        try:
            cmd = bytearray(
                [
                    address,  # 设备地址
                    0x03,  # 功能码：读保持寄存器
                    (reg_addr >> 8) & 0xFF,  # 起始地址高字节
                    reg_addr & 0xFF,  # 起始地址低字节
                    0x00,
                    count,  # 寄存器数量
                ]
            )

            # 添加CRC校验
            crc = _calculate_crc(cmd)
            cmd.append(crc & 0xFF)  # CRC低字节
            cmd.append((crc >> 8) & 0xFF)  # CRC高字节

            # 清空接收缓冲区
            dummy_buffer = bytearray(64)
            _uart.read(dummy_buffer)

            # 发送命令（转换为bytes）
            _uart.write(bytes(cmd))
            utime.sleep_ms(200)

            # 读取响应
            response_buffer = bytearray(64)
            bytes_received = _uart.read(response_buffer)

            if bytes_received >= (3 + count * 2 + 2):  # 最小响应长度
                response = response_buffer[:bytes_received]

                # 验证响应
                if _validate_response(response, address, 0x03, 3 + count * 2 + 2):
                    print(
                        "\n[MODBUS] Found data at register 0x{:04X}:".format(reg_addr)
                    )

                    # 解析并显示数据
                    for i in range(count):
                        value = (response[3 + i * 2] << 8) | response[3 + i * 2 + 1]
                        print(
                            "  Reg 0x{:04X}: {} (0x{:04X}) - V:{:.1f}, I:{:.2f}".format(
                                reg_addr + i, value, value, value / 10.0, value / 100.0
                            )
                        )

                    # 尝试解析为三相数据
                    if count >= 6:
                        va = (response[3] << 8) | response[4]
                        vb = (response[5] << 8) | response[6]
                        vc = (response[7] << 8) | response[8]
                        ia = (response[9] << 8) | response[10]
                        ib = (response[11] << 8) | response[12]
                        ic = (response[13] << 8) | response[14]

                        print(
                            "  Possible 3-phase: VA={:.1f}V VB={:.1f}V VC={:.1f}V IA={:.2f}A IB={:.2f}A IC={:.2f}A".format(
                                va / 10.0,
                                vb / 10.0,
                                vc / 10.0,
                                ia / 100.0,
                                ib / 100.0,
                                ic / 100.0,
                            )
                        )

            utime.sleep_ms(100)  # 避免过快扫描

        except Exception as e:
            # 静默处理错误，继续扫描
            pass

    print("\n[MODBUS] Scan completed")


def test_modbus():
    """测试Modbus通信"""
    print("[MODBUS] Testing Modbus communication...")

    # 测试温湿度传感器
    temp_data = read_temperature_humidity()
    if temp_data:
        print(
            "[MODBUS] Temperature: {}°C, Humidity: {}%".format(
                temp_data["temperature"], temp_data["humidity"]
            )
        )

    # 测试电力仪表
    power_data = read_power_meter()
    if power_data:
        print(
            "[MODBUS] Voltage: {}V, Current: {}A".format(
                power_data["voltage"], power_data["current"]
            )
        )

    return temp_data is not None or power_data is not None
